/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.view;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JDialog;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

/**
 *
 * @author  Walter Lütgenau
 */
public class TreeNodeChooserDialog extends javax.swing.JDialog {

    /** A return status code - returned if Cancel button has been pressed */
    public static final int RET_CANCEL = 0;
    /** A return status code - returned if OK button has been pressed */
    public static final int RET_OK = 1;

    /** Creates new form NodeChooserDialog */
    public TreeNodeChooserDialog(JDialog parent, boolean modal) {
        super(parent, modal);
    }

    public TreeNodeChooserDialog(JDialog parent, boolean modal, DefaultMutableTreeNode root) {
        super(parent, modal);
        init(root);
    }

    public void init(DefaultMutableTreeNode root) {
        initComponents();

        returnStatus = RET_CANCEL;

        nodeTree.setModel(new DefaultTreeModel(root));

        nodeTree.addTreeSelectionListener(new TreeSelectionListener() {

            public void valueChanged(TreeSelectionEvent e) {
                if (nodeTree.getSelectionCount() != 1)
                    return;
                TreePath path = nodeTree.getSelectionPath();
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();

                pathTextField.setText(node.getUserObject().toString());
                okButton.setEnabled(true);

                returnStatus = RET_OK;
            }
        });

        MouseListener ml = new MouseAdapter() {

            public void mousePressed(MouseEvent e) {
                int selRow = nodeTree.getRowForLocation(e.getX(), e.getY());
                TreePath selPath = nodeTree.getPathForLocation(e.getX(), e.getY());
                if (selRow != -1)
                    if (e.getClickCount() == 2)
                        doClose(RET_OK);
            }
        };
        nodeTree.addMouseListener(ml);


    }

    /** @return the return status of this dialog - one of RET_OK or RET_CANCEL */
    public int getReturnStatus() {
        return returnStatus;
    }

    /**
     * A matcher used to retrieve a particular node from the tree.
     */
    public interface Matcher {

        /**
         * Check, if the provided user object from a DefaultMutableTreeNode matches.
         * @param userObject The user object
         * @return Return the result of the check
         */
        public boolean matches(Object userObject);
    }

    /**
     * Find the node, that matches. Select it and scroll to it.
     * @param matcher The matcher used to retrieve the node
     */
    public void setSelectedNode(Matcher matcher) {
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) nodeTree.getModel().getRoot();
        DefaultMutableTreeNode selected = getMatchingNode(root, matcher);
        if (selected == null)
            return;

        TreePath path = new TreePath(selected.getPath());
        nodeTree.setSelectionPath(path);
        nodeTree.scrollPathToVisible(path);
    }

    protected DefaultMutableTreeNode getMatchingNode(DefaultMutableTreeNode node, Matcher matcher) {
        if (matcher.matches(node.getUserObject()))
            return node;

        for (int i = 0; i < node.getChildCount(); i++) {
            DefaultMutableTreeNode match = getMatchingNode((DefaultMutableTreeNode) node.getChildAt(i), matcher);
            if (match != null)
                return match;
        }

        return null;
    }

    public DefaultMutableTreeNode getSelectedNode() {
        TreePath selected = nodeTree.getSelectionModel().getSelectionPath();
        if (selected == null)
            return null;

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) selected.getLastPathComponent();

        return node;
    }

    public void setCellRenderer(TreeCellRenderer renderer) {
        nodeTree.setCellRenderer(renderer);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        okButton = new javax.swing.JButton();
        cancelButton = new javax.swing.JButton();
        promptLabel = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        nodeTree = new javax.swing.JTree();
        jLabel1 = new javax.swing.JLabel();
        pathTextField = new javax.swing.JTextField();

        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("offset/nodes/client/view/resources/ClientBundle"); // NOI18N
        setTitle(bundle.getString("chooser.title")); // NOI18N
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                closeDialog(evt);
            }
        });

        okButton.setText("OK");
        okButton.setEnabled(false);
        okButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectOk(evt);
            }
        });

        cancelButton.setText("Cancel");
        cancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectCancel(evt);
            }
        });

        promptLabel.setText(bundle.getString("chooser.prompt")); // NOI18N

        nodeTree.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        jScrollPane1.setViewportView(nodeTree);

        jLabel1.setText(bundle.getString("chooser.nodeName")); // NOI18N

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGap(19, 19, 19)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(cancelButton))
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(promptLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 506, Short.MAX_VALUE)
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                            .addComponent(jLabel1)
                            .addGap(10, 10, 10)
                            .addComponent(pathTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 438, Short.MAX_VALUE))))
                .addGap(28, 28, 28))
        );

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton});

        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(21, 21, 21)
                .addComponent(promptLabel)
                .addGap(24, 24, 24)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 162, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1))
                .addGap(19, 19, 19)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cancelButton)
                    .addComponent(okButton))
                .addGap(20, 20, 20))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void selectOk(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectOk
        doClose(RET_OK);
    }//GEN-LAST:event_selectOk

    private void selectCancel(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectCancel
        doClose(RET_CANCEL);
    }//GEN-LAST:event_selectCancel

    /** Closes the dialog */
    private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
        doClose(RET_CANCEL);
    }//GEN-LAST:event_closeDialog

    private void doClose(int retStatus) {
        returnStatus = retStatus;
        setVisible(false);
        dispose();
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton cancelButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTree nodeTree;
    private javax.swing.JButton okButton;
    private javax.swing.JTextField pathTextField;
    private javax.swing.JLabel promptLabel;
    // End of variables declaration//GEN-END:variables
    private int returnStatus = RET_CANCEL;
}
